'use strict';

/**
 * @author jiyanliang|weizhiqiang
 * @class sf.b2c.mall.framework.comm
 * @description comm通信基类
 */
define([
        'zepto',
        'zepto.cookie',
        'can',
        'underscore',
        'md5',
        'store',
        'sf.b2c.mall.business.config',
        'sf.b2c.mall.api.security.type'
    ],

    function($, cookie, can, _, md5, store, SFBizConfig, SecurityType) {

        window.getMetaData = function(key) {
            var meta = document.getElementsByTagName('meta');
            var share_desc = '';
            for (i in meta) {
                if (typeof meta[i].name != "undefined" && meta[i].name.toLowerCase() == key) {
                    share_desc = meta[i].content;
                }
            }

            return share_desc;
        }

        window.title = window.document.title;

        window.getDescription = (function() {
            return window.getMetaData('description');
        })(window);

        window.getShareIcon = (function() {
            return window.getMetaData('shareicon');
        })(window);

        var ERROR_CODE_TOKEN_ERROR = -360;
        var ERROR_CODE_TOKEN_EXPIRE = -300;
        var ERROR_CODE_SIGNATURE_ERROR = -180;
        var ERROR_CODE_ACCESS_DENIED = -160;

        var TOKEN_AND_SIGNATURE_ERROR_GROUP = [
            ERROR_CODE_TOKEN_ERROR,
            ERROR_CODE_TOKEN_EXPIRE,
            ERROR_CODE_SIGNATURE_ERROR,
            ERROR_CODE_ACCESS_DENIED
        ];

        /**
         * @note 暂时关闭错误提交
         * @param {String}  errorMessage   错误信息
         * @param {String}  scriptURI      出错的文件
         * @param {Long}    lineNumber     出错代码的行号
         * @param {Long}    columnNumber   出错代码的列号（IE支持）
         * @param {Long}    error          错误堆栈 （chrome30支持）
         */
        // window.onerror = function(errorMessage, scriptURI, lineNumber, columnNumber, error) {
        //   var msgs = [];
        //   msgs.push("errorMessage：", errorMessage);
        //   msgs.push(",file：", scriptURI);
        //   msgs.push(",errorplace：", lineNumber + 'line,' + columnNumber + 'column');
        //   msgs.push(",stack：", error);

        //   can.ajax({
        //         url: "http://stat.t.sfht.com/b.txt?" + msgs.join(''),
        //         type: 'post',
        //         contentType: "application/x-www-form-urlencoded; charset=UTF-8"
        //       })
        // };

        can.route.ready();

        var _aid = $.fn.cookie('_aid');

        var addParamsToCookies = function() {
            if (window.userinfo) {
                // console.log(JSON.stringify(window.userinfo));
                return addParamsByAppSetting(window.userinfo);
            }

            var params = can.route.attr();

            if (params.cookieInfo) {
                $.fn.cookie(_aid + '_uinfo', params.cookieInfo);
            }

            if (params.appId) {
                SFBaseComm._aid = params.appId
                $.fn.cookie('_aid', params.appId, {
                    path: '/',
                    domain: '.tepin.hk'
                });
            }

            if (params.csrfToken) {
                store.set('csrfToken', params.csrfToken);
                $.fn.cookie(SFBaseComm._aid + '_ct', 1, {
                    path: '/',
                    domain: '.tepin.hk'
                });
            }

            if (params.token) {
                $.fn.cookie(SFBaseComm._aid + '_tk', window.decodeURIComponent(params.token), {
                    path: '/',
                    domain: '.tepin.hk'
                });
            }

            if (params.deviceId) {
                $.fn.cookie('__da', params.deviceId, {
                    path: '/',
                    domain: '.tepin.hk'
                });
            }
        }

        var addParamsByAppSetting = function(params) {
            params = _.isArray(params) ? params[0] : params;

            if (params.appInfo && params.appInfo.appId) {
                SFBaseComm._aid = params.appInfo.appId
                $.fn.cookie('_aid', params.appInfo.appId, {
                    path: '/',
                    domain: '.tepin.hk'
                });
            }

            if (params.token && params.token.webCsrfToken) {
                store.set('csrfToken', params.token.webCsrfToken);
                $.fn.cookie(SFBaseComm._aid + '_ct', 1, {
                    path: '/',
                    domain: '.tepin.hk'
                });
            } else {
                $.fn.cookie(SFBaseComm._aid + '_ct', null);
            }

            if (params.token && params.token.cookieInfo) {
                $.fn.cookie(SFBaseComm._aid + '_uinfo', params.token.cookieInfo);
            } else {
                $.fn.cookie(SFBaseComm._aid + '_uinfo', null);
            }

            if (params.token && params.token.webToken) {
                $.fn.cookie(SFBaseComm._aid + '_tk', window.decodeURIComponent(params.token.webToken), {
                    path: '/',
                    domain: '.tepin.hk'
                });
            } else {
                $.fn.cookie(SFBaseComm._aid + '_tk', null);
            }

            if (params.device && params.device.deviceId) {
                $.fn.cookie('__da', params.device.deviceId, {
                    path: '/',
                    domain: '.tepin.hk'
                });
            }
        }
        var SFBaseComm = can.Construct.extend({

            /**
             * api的定义需要被每个子类复写
             * @type {Object}
             */
            api: {},

            /**
             * @function sf.b2c.mall.framework.comm.buildRequestData
             * @description 通过与定义的API接口和用户通过this.data传入的参数构建向服务端发起请求需要用到的数据
             * @return {Object} 向服务端提交的数据结构
             */
            buildRequestData: function() {
                if (this.api) {

                    // 判断fixture特性
                    this.fixture = false;
                    if (this.data && this.data.fixture) {
                        this.fixture = true;
                    }

                    this.https = false;
                    if (this.data && this.data['https']) {
                        this.https = true;
                    }

                    if (!SFBizConfig.setting.openHttps) {
                        this.https = false;
                    }

                    var requestData = {};

                    // 添加每个请求的_mt参数
                    _.extend(requestData, {
                        _mt: this.api.METHOD_NAME
                    });

                    // 提供公共参数
                    _.extend(requestData, this.api.COMMON);

                    var key;
                    // 添加必填参数
                    for (key in this.api.REQUIRED) {
                        requestData[key] = this.data[key];
                    }

                    // 添加选填参数
                    for (key in this.api.OPTIONAL) {
                        requestData[key] = this.data[key];
                    }

                    return requestData;
                }
            },
            /**
             * @function sf.b2c.mall.framework.comm.buildRequestDataRestful
             * @description 通过与定义的API接口和用户通过this.data传入的参数构建向服务端发起请求需要用到的数据
             * @return {Object} 向服务端提交的数据结构
             */
            buildRequestDataRestful: function() {
                if (this.api) {
                    var requestData = {};
                    // 提供公共参数
                    _.extend(requestData, this.api.COMMON);
                    var key;
                    // 添加必填参数
                    for (key in this.api.REQUIRED) {
                        requestData[key] = this.data[key];
                    }
                    // 添加选填参数
                    for (key in this.api.OPTIONAL) {
                        requestData[key] = this.data[key];
                    }
                    return requestData;
                }
            },
            /**
             * @override
             * @function sf.b2c.mall.framework.comm.init
             * @description 初始化方法
             * @param  {Object} data 传入的涌来提交服务端的数据
             */
            init: function(data) {
                addParamsToCookies();
                this.setData(data);
            },

            /**
             * @function sf.b2c.mall.framework.setData
             * @description 修改请求参数
             */
            setData: function(data) {
                this.data = data;
            },

            /**
             * @function sf.b2c.mall.framework.sendRequest
             * @description 构建请求
             * @param {boolean} isForceUserLogin 是否需要强制用户登录
             * @return {Object} can.Deferred
             */
            sendRequest: function(isForceUserLogin, type) {

                //step1 调用子业务类进行数据校验
                var checkResult = this.validate(isForceUserLogin);

                if (checkResult !== true) {
                    return checkResult;
                }

                //step2 构建ajax请求数据，放到baseCommon的全局变量中，可以支持多个请求一起发送
                var requestData = this.buildRequestData();

                if (type == 'jsonp' && SFBizConfig.setting.openHttps) {
                    return this.jsonp(requestData);
                }

                //step3 发送请求,获得返回数据
                return this.request(requestData, isForceUserLogin);
            },
            /**
             * @function sf.b2c.mall.framework.sendRequestRestful
             * @description 构建请求
             * @return {Object} can.Deferred
             */
            sendRequestRestful: function() {
                //构建ajax请求数据，放到baseCommon的全局变量中，可以支持多个请求一起发送
                var requestData = this.buildRequestDataRestful();
                //发送请求,获得返回数据
                return this.requestRestful(requestData);
            },
            /**
             * @function sf.b2c.framework.comm.validate
             * @description 根据用户SecurityType进行检验，同时也会检验比天字段是否写入
             * @returns {Error|Boolean} 错误对象|验证成功
             */
            validate: function(isForceUserLogin) {
                // 检查必填字段，如果没有必填字段直接抛错
                if (this.api) {
                    if (!this.api.METHOD_NAME) {
                        return '缺少_mt';
                    }

                    for (var key in this.api.REQUIRED) {
                        if (!_.has(this.data, key)) {
                            return new Error('缺少必填字段' + key);
                        }
                    }
                }

                //根据action校验是否登录
                if (this.api.SECURITY_TYPE === SecurityType.UserLogin.name) {
                    if (!this.checkUserLogin()) {
                        if (isForceUserLogin) {
                            this.goToLogin();
                        } else {
                            return new Error('该请求需要在登录后发起');
                        }
                    }
                }

                return true;
            },

            addParamsToCookies: function() {
                // 如果在Hash中有csrfToke直接替换
                var params = can.route.attr();

                if (params.cookieInfo) {
                    $.fn.cookie(_aid + '_uinfo', params.cookieInfo);
                }

                if (params.appId) {
                    SFBaseComm._aid = params.appId
                    $.fn.cookie('_aid', params.appId, {
                        path: '/',
                        domain: '.tepin.hk'
                    });
                }

                if (params.csrfToken) {
                    store.set('csrfToken', params.csrfToken);
                    $.fn.cookie(SFBaseComm._aid + '_ct', 1, {
                        path: '/',
                        domain: '.tepin.hk'
                    });
                }

                if (params.token) {
                    $.fn.cookie(SFBaseComm._aid + '_tk', window.decodeURIComponent(params.token), {
                        path: '/',
                        domain: '.tepin.hk'
                    });
                }

                if (params.deviceId) {
                    $.fn.cookie('__da', params.deviceId, {
                        path: '/',
                        domain: '.tepin.hk'
                    });
                }
            },

            /**
             * @function sf.b2c.mall.framework.checkUserLogin
             * @description 检查用户是否登陆
             * @return {Boolean} 用户是否登陆
             */
            checkUserLogin: function() {
                // var csrf = window.localStorage ? window.localStorage.getItem('csrfToken') : $.jStorage.get('csrfToken');

                addParamsToCookies();

                var csrf = store.get('csrfToken');
                return !!($.fn.cookie(SFBaseComm._aid + '_ct') && csrf);
            },

            /**
             * @function sf.b2c.mall.framework.goToLogin
             * @description 跳转到登陆
             */
            goToLogin: function() {
                // 获取现在的pathname作为跳转的from依据
                // var path = window.location.pathname;
                var path = window.location.href;
                if (path !== SFBizConfig.setting.login) {
                    window.location.href = "http://m.tepin.hk/user/login.html" + '?from=' + escape(path);
                }
            },

            /**
             * @function sf.b2c.mall.framework.comm.access
             * @description 返回的参数是否正确
             * @param  {Map}      response          服务端返回的信息
             * @param  {Boolean}  isForceUserLogin  是否需要强制登陆
             */
            access: function(response, isForceUserLogin) {
                if (response.stat.code === 0 && response.content[0] && response.stat.stateList[0].code === 0) {
                    return true;
                } else if (_.contains(TOKEN_AND_SIGNATURE_ERROR_GROUP, response.stat.code) && isForceUserLogin) {
                    this.goToLogin();
                } else {
                    return false;
                }
            },

            /**
             * @function sf.b2c.mall.framework.comm.encrypt
             * @param  {Map}    params      需要加密的参数
             * @param  {String} appendWord  加言
             */
            encrypt: function(params, appendWord) {
                var arr = [];

                // 将Map变成Array，使用key=value的方式进行拼接
                _.each(params, function(value, key) {
                    arr.push(key + '=' + value);
                });

                // 以ascii进行排序
                arr.sort();

                // 将队列拼接成String
                var str = arr.join('');
                str = str + appendWord;

                // 做md5加密
                return md5(str);
            },

            /**
             * @function sf.b2c.mall.framework.comm.sign
             * @param  {Map}      params           参与请求签名的实体
             * @param  {Boolean}  isForceUserLogin 是否需要强制登陆
             */
            sign: function(params, isForceUserLogin) {
                var map = {
                    'None': function(data, force) {
                        return _.extend(data, {
                            _sig: this.encrypt(data, SFBizConfig.setting['none_append_word'])
                        });
                    },

                    'RegisteredDevice': function(data, force) {
                        return _.extend(data, {
                            _sig: this.encrypt(data, SFBizConfig.setting['none_append_word'])
                        });
                    },

                    'UserLogin': function(data, force) {
                        // var csrf = window.localStorage ? window.localStorage.getItem('csrfToken') : $.jStorage.get('csrfToken');
                        var csrf = store.get('csrfToken');

                        if (csrf) {
                            return _.extend(data, {
                                _sig: this.encrypt(data, csrf)
                            });
                        } else {
                            this.goToLogin();
                        }
                    }
                };

                if (_.isFunction(map[this.api.SECURITY_TYPE])) {
                    // 过滤所有的undefined和null的数据
                    _.each(params, function(value, key, list) {
                        if (_.isUndefined(value) || _.isNull(value)) {
                            delete params[key];
                        }
                    });

                    // 将参数附加上必须要传递的标记
                    var required = _.extend(params, SFBizConfig.setting['default_header']);
                    required = _.extend(required, {
                        _aid: SFBaseComm._aid
                    });

                    // 做加密生产_sig对象
                    var _sig = map[this.api.SECURITY_TYPE].call(this, required, isForceUserLogin);

                    // 返回数据可以直接做请求
                    return _.extend(required, _sig);
                } else {
                    return params;
                }
            },

            jsonp: function(data) {
                data = _.extend(data, { _cb: 'fengqujsonpcallback', _: Date.now() });

                var def = can.Deferred();

                var that = this;
                window.fengqujsonpcallback = function(data) {
                    if (that.access(data, false)) {
                        def.resolve(data.content[0])
                    } else {
                        if (data.stat.stateList.length == 0) {
                            def.reject(data.stat.code);
                        } else {
                            def.reject(data.stat.stateList[0].code, data.stat.stateList[0].msg);
                        }
                    }
                }

                var scriptTag = document.createElement('script');
                scriptTag.src = 'https://www.tepin.hk/m.api' + '?' + $.param(this.sign(data));
                scriptTag.type = "text/javascript"
                document.body.appendChild(scriptTag);

                return def;
            },

            /**
             * @function sf.b2c.mall.framework.request
             * @param  {Map}     data             请求参数
             * @param  {Boolean} isForceUserLogin 是否需要强制登陆
             * @return {can.Deferred}
             */
            request: function(data, isForceUserLogin) {
                var def = can.Deferred();
                var that = this;

                var successCallback = function(response) {
                    if (response && response.stat) {
                        that.serverTime = response.stat.systime;
                    }

                    if (that.access(response, isForceUserLogin)) {
                        that.afterRequest(data._mt, response.content[0]);
                        def.resolve(response.content[0]);
                    } else {
                        if (response.stat.stateList.length == 0) {

                            // -180则清空所有storage
                            if (response.stat.code == ERROR_CODE_SIGNATURE_ERROR) {
                                store.clear();
                                that.goToLogin();
                            }

                            def.reject(response.stat.code);
                        } else {

                            // -180则清空所有storage
                            if (response.stat.code == ERROR_CODE_SIGNATURE_ERROR) {
                                store.clear();
                                that.goToLogin();
                            }

                            def.reject(response.stat.stateList[0].code, response.stat.stateList[0].msg);
                        }
                    }
                }

                var failCallback = function(error) {
                    def.reject(error);
                }

                $.ajax({
                        url: that.https ? SFBizConfig.setting.httpsapi.url : SFBizConfig.setting.api.url,
                        type: 'post',
                        contentType: "application/x-www-form-urlencoded; charset=UTF-8",
                        data: that.sign(data),
                        fixture: that.fixture,
                        success: function(response) {
                            successCallback(response);
                        },
                        fail: function(error) {
                            failCallback(error);
                        }
                    })
                    .done(function(response) {
                        successCallback(response);
                    })
                    .fail(function(error) {
                        failCallback(error);
                    });

                return def;
            },
            /**
             * @function sf.b2c.mall.framework.request
             * @param  {Map}     data             请求参数
             * @return {can.Deferred}
             */
            requestRestful: function(data) {
                var def = can.Deferred();
                var that = this;
                // var successCallback = function(response) {
                //     // if (response.returnCode===0) {
                //       def.resolve(response);
                //     // } else {
                //       // def.reject(response.returnCode);
                //     // }
                // }
                // var failCallback = function(error) {
                //     def.reject(error);
                // }
                $.ajax({
                        url: SFBizConfig.setting.api.baseurl + that.api.PATH_NAME,
                        type: that.api.HTTP_METHOD,
                        contentType: "application/x-www-form-urlencoded; charset=UTF-8",
                        data: _.extend(data || {}, {_t: Date.now()}),
                        // success: function(response) {
                        //     successCallback(response);
                        // },
                        // fail: function(error) {
                        //     failCallback(error);
                        // }
                    })
                    .done(function(response) {
                        def.resolve(response);
                        // successCallback(response);
                    })
                    .fail(function(error) {
                        def.reject(error);
                        // failCallback(error);
                    });
                return def;
            },
            /**
             * @description 通过服务端接口每次从stat中返回的system在客户端中保留服务端时间
             * @return {Int} 服务端时间的时间戳
             */
            getServerTime: function() {
                return this.serverTime;
            },

            /**
             * @description 请求后处理回调
             * @function sf.b2c.mall.framework.comm.afterRequest
             * @param  {String} mt
             * @param  {Map} response
             */
            afterRequest: function(mt, response) {
                var map = {
                    'user.webLogin': function(response) {

                        store.set('csrfToken', response.csrfToken);

                        // if (window.localStorage) {
                        //   window.localStorage.setItem('csrfToken', response.csrfToken);
                        // } else {
                        //   $.jStorage.set('csrfToken', response.csrfToken);
                        // }
                    },

                    "user.partnerLogin": function(response) {
                        store.set('csrfToken', response.csrfToken);
                    },

                    "user.mobileRegister": function(response) {
                        store.set('csrfToken', response.csrfToken);
                    }
                };

                if (_.isFunction(map[mt])) {
                    map[mt].call(this, response);
                }
            },

            /**
             * @description 调用简单的ajax请求
             * @param  {Map} data 请求$.ajaxSetting
             * @return {Object} can.Deferred
             */
            ajax: function(data) {
                return can.ajax(data);
            }
        });

        SFBaseComm.register = function(aid) {
            if (_aid) {
                this._aid = _aid;
            } else {
                this._aid = aid;
            }
        }

        return SFBaseComm;
    });
